﻿using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Reflection;
using System.Text;

namespace DotNetExtensions.Core.Helpers
{
    public class TypeHelper
    {
        public static Assembly[] FindAssemblys(string module)
        {
            return AppDomain.CurrentDomain.GetAssemblies().Where(a => a.GetModules().Any(m => m.Name == module)).ToArray();
        }
        public static Type TryParse(string module, string clazz)
        {
            if (string.IsNullOrEmpty(module) || string.IsNullOrEmpty(clazz)) throw new ArgumentNullException();

            var assemblys = FindAssemblys(module);

            if (assemblys == null || assemblys.Length == 0) throw new ArgumentException($"Module `{module}` not find ");

            Type type = assemblys.First().GetType(clazz);

            if (type == null) throw new ArgumentException($"Type `{clazz}` not find ");

            return type;
        }
        public static object CreateInstance(string module, string clazz)
        {
            if (string.IsNullOrEmpty(module) || string.IsNullOrEmpty(clazz)) throw new ArgumentNullException();
            var assemblys = FindAssemblys(module);
            if (assemblys == null || assemblys.Length == 0) throw new ArgumentException($"Module `{module}` not find ");
            var assembly = assemblys.First();
            return assembly.CreateInstance(clazz);
        }
        public static TypeInvoker TryParse(Type type)
        {
            TypeInvoker invoker = new TypeInvoker();
            invoker.Clazz = type.FullName;
            invoker.Module = type.Module.Name;
            return invoker;
        }
        public static bool IsBasicType(Type type)
        {
            if (type == typeof(string)) return true;
            if (type == typeof(String)) return true;
            if (type == typeof(int)) return true;
            if (type == typeof(Int16)) return true;
            if (type == typeof(Int32)) return true;
            if (type == typeof(Int64)) return true;
            if (type == typeof(long)) return true;
            if (type == typeof(Boolean)) return true;
            if (type == typeof(bool)) return true;
            if (type == typeof(float)) return true;
            if (type == typeof(double)) return true;
            if (type == typeof(decimal)) return true;
            if (type == typeof(Decimal)) return true;
            if (type == typeof(uint)) return true;
            if (type == typeof(ulong)) return true;
            if (type == typeof(ushort)) return true;
            if (type == typeof(short)) return true;
            if (type == typeof(UInt16)) return true;
            if (type == typeof(UInt32)) return true;
            if (type == typeof(UInt64)) return true;
            if (type == typeof(DateTime)) return true;
            if (type == typeof(DateTime?)) return true;

            return false;
        }
        public static bool IsNumberType(Type type)
        {
            if (type == typeof(int)) return true;
            if (type == typeof(long)) return true;
            if (type == typeof(float)) return true;
            if (type == typeof(double)) return true;
            if (type == typeof(decimal)) return true;
            if (type == typeof(uint)) return true;
            if (type == typeof(ulong)) return true;
            if (type == typeof(ushort)) return true;
            if (type == typeof(short)) return true;

            return false;
        }
        public static bool IsEnumType(Type type)
        {
            return type.IsEnum
                || type.BaseType == typeof(Enum)
                || (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>) && Nullable.GetUnderlyingType(type).IsEnum);
        }

        public static bool IsBooleanType(Type type)
        {
            return type == typeof(bool)
                || (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>) && Nullable.GetUnderlyingType(type) == typeof(bool));
        }

        public static bool IsLongType(Type type)
        {
            return type == typeof(long);
        }
        public static object DefaultValue(Type type)
        {
            if (type == typeof(string)) return null;
            if (type == typeof(String)) return null;
            if (type == typeof(int)) return 0;
            if (type == typeof(Int16)) return 0;
            if (type == typeof(Int32)) return 0;
            if (type == typeof(Int32?)) return null;
            if (type == typeof(Int64)) return 0;
            if (type == typeof(Int64?)) return null;
            if (type == typeof(long)) return 0;
            if (type == typeof(long?)) return null;
            if (type == typeof(Boolean)) return false;
            if (type == typeof(Boolean?)) return null;
            if (type == typeof(bool)) return false;
            if (type == typeof(bool?)) return null;
            if (type == typeof(float)) return 0;
            if (type == typeof(double)) return 0;
            if (type == typeof(decimal)) return 0;
            if (type == typeof(decimal?)) return null;
            if (type == typeof(Decimal)) return 0;
            if (type == typeof(uint)) return 0;
            if (type == typeof(ulong)) return 0;
            if (type == typeof(ushort)) return 0;
            if (type == typeof(short)) return 0;
            if (type == typeof(UInt16)) return 0;
            if (type == typeof(UInt32)) return 0;
            if (type == typeof(UInt64)) return 0;
            if (type == typeof(DateTime)) return DateTime.MinValue;
            if (type == typeof(DateTime?)) return DateTime.MinValue;

            return null;
        }

        public static bool IsArray(Type type)
        {
            if (type == null || IsBasicType(type)) return false;
            if (type == typeof(Array)) return true;
            return type.IsArray;
        }
        
        public static bool IsEnumerable(Type type)
        {
            if (type == null || IsBasicType(type)) return false;
            var interfaces = type.GetInterfaces();

            if (type.IsArray) return false;
            if (type.IsGenericType == false) return false;
            foreach (var item in interfaces)
            {
                if (item.Name.Contains("IList")) return true;
                if (item.Name.Contains("IEnumerable")) return true;
                if (item.Name.Contains("ICollection")) return true;
            }

            return false;
        }

       
    }
}
